<?php

	namespace org\tekuna\framework\info;

	use org\tekuna\base\Tekuna;

	use org\tekuna\core\configuration\XmlConfiguration;
	use org\tekuna\core\context\Context;
	use org\tekuna\core\event\Event;
	use org\tekuna\core\event\AbstractEventListener;
	use org\tekuna\core\event\TriggeredEvent;
	use org\tekuna\core\event\HandledListener;

	use org\tekuna\framework\response\BeforeResponseSendEvent;
	use org\tekuna\framework\request\CliRequest;
	use org\tekuna\framework\request\HttpRequest;
	
	
	/**
	 * Helper class that provides information about various internal
	 * objects when an InformationEvent was triggered.
	 */
	class FrameworkInformationProviderListener extends AbstractEventListener {

		public function handlesEvent(Event $objEvent) {

			return $objEvent instanceof InformationEvent;
		}
		
		public function handleEvent(Event $objEvent) {
			
			$this -> provideRequestInformation($objEvent);
			$this -> provideContextInformation($objEvent);
			$this -> provideConfigurationInformation($objEvent);
			$this -> provideEventManagerInformation($objEvent);
			$this -> provideClassLoaderInformation($objEvent);
		}
			
		private function provideRequestInformation(InformationEvent $objInformationEvent) {

			$objRequest = $this -> getApplicationContext() -> getRequest();
			$sOutput = '';
			
			$sOutput .= "Request Class: ". get_class($objRequest) ."\n";
			
			if ($objRequest instanceof HttpRequest) {
				
				$sOutput .= "Protocol: ". $objRequest -> getRequestProtocol() ."\n";
				$sOutput .= "Import Encoding: ". $objRequest -> getImportEncoding() ."\n";
				$sOutput .= "HTTP Method: ". $objRequest -> getRequestMethod() ."\n";
				$sOutput .= "Action: ". $objRequest -> getRequestAction() ."\n";
				$sOutput .= "Authenticated User: ". $objRequest -> getAuthenticatedUser() ."\n";
				
				$sOutput .= "\nGET Parameters\n";
				$sOutput .= "--------------\n";
				foreach ($objRequest -> getAllGetValues() as $sParameter => $sValue) {
	
					$objFilter = $objRequest -> getGetFilter($sParameter);
					if ($objFilter === null) {
	
						$sFilterClass = '*';
					}
					else {
	
						$sFilterClass = get_class($objFilter);
					}
	
					$sOutput .= '   '. sprintf('%-40s', $sParameter .' = '. $sValue) ."($sFilterClass)\n";
				}
	
				$sOutput .= "\nPOST Parameters\n";
				$sOutput .= "---------------\n";
				foreach ($objRequest -> getAllPostValues() as $sParameter => $sValue) {
	
					$objFilter = $objRequest -> getGetFilter($sParameter);
					if ($objFilter === null) {
	
						$sFilterClass = '*';
					}
					else {
	
						$sFilterClass = get_class($objFilter);
					}
	
					$sOutput .= '   '. sprintf('%-40s', $sParameter .' = '. $sValue) ."($sFilterClass)\n";
				}
				
				// TODO: cookies
				
				$sOutput .= "\nUploaded Files\n";
				$sOutput .= "--------------\n";
				foreach ($objRequest -> getAllFiles() as $sFileId => $objFile) {
	
					$objFilter = $objRequest -> getFileFilter($sFileId);
					if ($objFilter === null) {
	
						$sFilterClass = '**';
					}
					else {
	
						$sFilterClass = get_class($objFilter);
					}
					
					$sOutput .= "   ". sprintf('%-40s', $sFileId.':') ."($sFilterClass)\n";
					$sOutput .= '      Filename: '. $objFile -> getFileName() ."\n";
					$sOutput .= '      Temp. File: '. $objFile -> getTempName() ."\n";
					$sOutput .= '      Size: '. $objFile -> getFileSize() ." Bytes\n";
					$sOutput .= '      MIME Type: '. $objFile -> getMimeType() ."\n";
					$sOutput .= '      Error Code: '. $objFile -> getErrorCode() ."\n\n";
				}
				
				$sOutput .= "\n";
				$sOutput .= '* Default Filter = '. get_class($objRequest -> getDefaultFilter()) ."\n";
				$sOutput .= '** Default File Filter = '. get_class($objRequest -> getDefaultFileFilter()) ."\n";
			}
			
			if ($objRequest instanceof CliRequest) {

				$sOutput .= "\nArguments\n";
				$sOutput .= "---------\n";
				foreach ($objRequest -> getAllArguments() as $sArgument => $sValue) {
	
					$objFilter = $objRequest -> getArgumentFilter($sArgument);
					if ($objFilter === null) {
	
						$sFilterClass = '*';
					}
					else {
	
						$sFilterClass = get_class($objFilter);
					}
	
					$sOutput .= '   '. sprintf('%-40s', $sArgument .' = '. $sValue) ."($sFilterClass)\n";
				}

				$sOutput .= "\n";
				$sOutput .= '* Default Filter = '. get_class($objRequest -> getDefaultFilter()) ."\n";
			}
			
			// add new info section
			$objInformationEvent -> addInfoSection('Request', $sOutput);
		}
		
		private function provideContextInformation(InformationEvent $objInformationEvent) {

			// add new info section
			$objInformationEvent -> addInfoSection('Current Context', $this -> getApplicationContext() -> __toString());
		}
		
		private function provideConfigurationInformation(InformationEvent $objInformationEvent) {
			
			$sOutput = '';
			if ($this -> getApplicationContext() -> getConfiguration() instanceof XmlConfiguration) {
				
				foreach ($this -> getApplicationContext() -> getConfiguration() -> getProcessedFiles() as $sFile) {
					
					$sOutput .= "  - $sFile\n";
				}
			}
			else {
				
				$sOutput .= "File list only available for XML configurations\n";
			}

			// add new info section
			$objInformationEvent -> addInfoSection('Used Configuration Files', $sOutput);
			
			$sOutput =  "Configuration Class: ". get_class($this -> getApplicationContext() -> getConfiguration()) ."\n";
			$sOutput .= $this -> getApplicationContext() -> getConfiguration() -> getRootElement() -> __toString();
			
			// add new info section
			$objInformationEvent -> addInfoSection('Loaded Configuration', $sOutput);
		}
		
		private function provideEventManagerInformation(InformationEvent $objInformationEvent) {
			
			$sOutput = '';
			
			$sOutput .= "Displayed in the order of their registration at the EventManager:\n";
			foreach ($this -> getApplicationContext() -> getEventManager() -> getRawListenersList() as $arrEventManager) {
				
				$sOutput .= "   - ". get_class($arrEventManager['listener']) ." (weight: $arrEventManager[weight])\n";
			}
			
			$sOutput .= "\nOrder of propagation of Events:\n";
			foreach ($this -> getApplicationContext() -> getEventManager() -> getRegisteredListeners() as $objListener) {
				
				$sOutput .= "  - ". get_class($objListener) ."\n";
			}
			
			$sOutput .= "\nEvents (E) and Handler (H) History\n";
			foreach ($this -> getApplicationContext() -> getEventManager() -> getEventsHistory() as $objTriggeredEvent) {

				$sOutput .= $this -> getTriggeredEventRecursive($objTriggeredEvent);
			}

			// add new info section
			$objInformationEvent -> addInfoSection('Event Listeners', $sOutput);
		}
		
		
		private function getTriggeredEventRecursive(TriggeredEvent $objTE, $iLevel = 0) {
			
			$sOutput = '';
			$sOutput .= str_repeat('  ', $iLevel);
			$sOutput .= '  E '. get_class($objTE -> getEvent()) ."\n";
			
			foreach ($objTE -> getHandledListeners() as $objHandledListener) {
				
				$sOutput .= $this -> getHandledListenerRecursive($objHandledListener, $iLevel+1);
			}
			
			return $sOutput;
		}
		
		private function getHandledListenerRecursive(HandledListener $objHL, $iLevel) {
			
			$sOutput = '';
			$sOutput .= str_repeat('  ', $iLevel);
			$sOutput .= '  H '. get_class($objHL -> getListener()) ."\n";
			
			foreach ($objHL -> getTriggeredEvents() as $objTriggeredEvent) {
				
				$sOutput .= $this -> getTriggeredEventRecursive($objTriggeredEvent, $iLevel+1);
			}
			
			return $sOutput;
		}
		
		
		private function provideClassLoaderInformation(InformationEvent $objInformationEvent) {
			
			$sOutput = '';
			foreach (Tekuna :: getInstance() -> getRegisteredClassLoaders() as $objClassLoader) {
				
				$sOutput .= "  - ". $objClassLoader -> __toString() ."\n";
			}
			
			// add new info section
			$objInformationEvent -> addInfoSection('Registered ClassLoaders', $sOutput);
		}
	}